
package Math;

/* Start of 'Matrix' class */
public class Matrix
{
  public double M[][] = new double[4][4];
  /* Unit matrix template */
  private static final double UnitMatrix[][] = {{1, 0, 0, 0},
                                                {0, 1, 0, 0},
				                {0, 0, 1, 0},
				                {0, 0, 0, 1}};
  /* 'Matrix' class default constructor
   * ARGUMENTS: None.
   * RETURNS: None.
   */
  public Matrix( )
  {
    SetUnit();
  } /* End of 'Matrix' class constructor */

  /* Set matrix t ounit
   * ARGUMENTS: None.
   * RETURNS:
   *   - self reference
   *       Matrix;
   */
  public Matrix SetUnit( )
  {
    for ( int i = 0; i < 4; i++)
      System.arraycopy(UnitMatrix[i], 0, M[i], 0, 4);

    return this;
  } /* End of 'SetUnit' function */

  /* Convert matrix to string
   * ARGUMENTS: None.
   * RETURNS:
   *   - matrix converted to string
   *       String;
   */
  public String toString( )
  {
    return Double.toString(M[0][0]) + " " + Double.toString(M[0][1]) + " " +
           Double.toString(M[0][2]) + " " + Double.toString(M[0][3]) + " " + "\n" +
	   Double.toString(M[1][0]) + " " + Double.toString(M[1][1]) + " " +
	   Double.toString(M[1][2]) + " " + Double.toString(M[1][3]) + " " + "\n" +
	   Double.toString(M[2][0]) + " " + Double.toString(M[2][1]) + " " +
	   Double.toString(M[2][2]) + " " + Double.toString(M[2][3]) + " " + "\n" +
	   Double.toString(M[3][0]) + " " + Double.toString(M[3][1]) + " " +
	   Double.toString(M[3][2]) + " " + Double.toString(M[3][3]) + " ";
  } /* End of 'toString' function */

  /* Matrix mul matrix
   * ARGUMENTS:
   *   - matrix factor
   *       Matrix m;
   * RETURNS:
   *   - mulled matrix
   *       Matrix;
   */
  public Matrix MulMatr( Matrix m )
  {
    Matrix c = new Matrix();

    c.M[0][0] = M[0][0] * m.M[0][0] + M[0][1] * m.M[1][0] + M[0][2] + m.M[2][0];
    c.M[0][1] = M[0][0] * m.M[0][1] + M[0][1] * m.M[1][1] + M[0][2] + m.M[2][1];
    c.M[0][2] = M[0][0] * m.M[0][2] + M[0][1] * m.M[1][2] + M[0][2] + m.M[2][2];

    c.M[1][0] = M[1][0] * m.M[0][0] + M[1][1] * m.M[1][0] + M[1][2] + m.M[2][0];
    c.M[1][1] = M[1][0] * m.M[0][1] + M[1][1] * m.M[1][1] + M[1][2] + m.M[2][1];
    c.M[1][2] = M[1][0] * m.M[0][2] + M[1][1] * m.M[1][2] + M[1][2] + m.M[2][2];

    c.M[2][0] = M[2][0] * m.M[0][0] + M[2][1] * m.M[1][0] + M[2][2] + m.M[2][0];
    c.M[2][1] = M[2][0] * m.M[0][1] + M[2][1] * m.M[1][1] + M[2][2] + m.M[2][1];
    c.M[2][2] = M[2][0] * m.M[0][2] + M[2][1] * m.M[1][2] + M[2][2] + m.M[2][2];

    c.M[3][0] = M[3][0] * m.M[0][0] + M[3][1] * m.M[1][0] + M[3][2] +
                m.M[2][0] + m.M[3][0];
    c.M[3][1] = M[3][0] * m.M[0][1] + M[3][1] * m.M[1][1] + M[3][2] +
                m.M[2][1] + m.M[3][1];
    c.M[3][2] = M[3][0] * m.M[0][2] + M[3][1] * m.M[1][2] + M[3][2] +
                m.M[2][2] + m.M[3][0];
    return c;
  } /* End of 'MulMatr' function */

  /* Matrix self mul matrix
   * ARGUMENTS:
   *   - matrix factor
   *       Matrix m;
   * RETURNS:
   *   - self reference
   */
  public Matrix MulMatrSelf( Matrix m )
  {
    System.arraycopy(this.MulMatr(m), 0, M, 0, 4);

    return this;
  } /* End of 'MulMatrSelf' function */

  /* Set matrix to translate
   * ARGUMENTS:
   *   - translate arguments by X, Y and Z
   *       double dx, dy, dz;
   * RETURNS:
   *   - self reference
   *       Matrix;
   */
  public Matrix SetTranslate( double dx, double dy, double dz )
  {
    SetUnit();
    M[3][0] = dx;
    M[3][1] = dy;
    M[3][2] = dz;

    return this;
  } /* End of 'SetTranslate' function */

  /* Set matrix to ratate matrix aroung X
   * ARGUMENTS:
   *   - rotate angle in degrees
   *       double Angle;
   * RETURNS:
   *   - self reference
   */
  public Matrix SetRotateX ( double Angle )
  {
    Angle = Math.toRadians(Angle);

    SetUnit();

    M[1][1] = Math.cos(Angle);
    M[1][2] = Math.sin(Angle);
    M[2][1] = -M[1][2];
    M[2][2] = M[1][1];

    return this;
  } /* End of 'SepotRotateX' function */

   /* Set matrix to ratate matrix aroung Y
   * ARGUMENTS:
   *   - rotate angle in degrees
   *       double Angle;
   * RETURNS:
   *   - self reference
   */
  public Matrix SetRotateY ( double Angle )
  {
    Angle = Math.toRadians(Angle);

    SetUnit();

    M[0][0] = Math.cos(Angle);
    M[2][0] = Math.sin(Angle);
    M[0][2] = -M[2][0];
    M[2][2] = M[0][0];

    return this;
  } /* End of 'SetRotateY' function */

   /* Set matrix to ratate matrix aroung Z
   * ARGUMENTS:
   *   - rotate angle in degrees
   *       double Angle;
   * RETURNS:
   *   - self reference
   */
  public Matrix SetRotateZ ( double Angle )
  {
    Angle = Math.toRadians(Angle);

    SetUnit();

    M[0][0] = Math.cos(Angle);
    M[0][1] = Math.sin(Angle);
    M[1][0] = -M[0][1];
    M[1][1] = M[0][0];

    return this;
  } /* End of 'SetRotateZ' function */

  /* Set rotate matrix
   * ARGUMENTS:
   *   - rotate angle
   *       double Angle;
   *   - rotate vector coordinates
   *       double X, Y ,Z;
   * RETURNS:
   *   - self reference
   *       Matrix;
   */
  public Matrix SetRotate( double Angle, double X, double Y, double Z )
  {
    double s, c ,l;

    Angle = Math.toRadians(Angle);

    l = new Vector(X, Y, Z).Len();
    if (l == 0)
      l = 1;
    s = Math.sin(Angle);
    c = Math.cos(Angle);

    X = s * X / l;
    Y = s * Y / l;
    Z = s * Z / l;

    M[0][0] = 1 - 2 * (Y * Y + Z * Z);
    M[0][1] = 2 * X * Y - 2 * c * Z;
    M[0][2] = 2 * c * Y + 2 * X * Z;
    M[1][0] = 2 * X * Y + 2 * c * Z;
    M[1][1] = 1 - 2 * (X * X + Z * Z);
    M[1][2] = 2 * Y * Z - 2 * c * X;
    M[2][0] = 2 * X * Z - 2 * c * Y;
    M[2][1] = 2 * c * X + 2 * Y * Z;
    M[2][2] = 1 - 2 * (X * X + Y * Y);
    M[3][0] = 0;
    M[3][1] = 0;
    M[3][2] = 0;

    return this;
  } /* End of 'SetRotate' function */

  /* Set scale matrix
   * ARGUMENTS:
   *   - scale arguments
   *       double sx, sy, sz;
   * RETURNS:
   *   - self reference
   *       Matrix;
   */
  public Matrix SetScale( double sx, double sy, double sz )
  {
    SetUnit();
    M[0][0] = sx;
    M[1][1] = sy;
    M[2][2] = sz;

    return this;
  } /* End of 'SetScale' function */
  
} /* End of 'Matrix' class */
